import tkinter as tk
from tkinter import ttk
import platform
import subprocess
from typing import Callable
from message_dialog import MessageDialog
from permission_checker import PermissionChecker


class PortScannerUI:
    """端口扫描器UI类"""

    def __init__(self, root: tk.Tk, scan_callback: Callable, cancel_callback: Callable):
        self.root = root
        self.scan_callback = scan_callback
        self.cancel_callback = cancel_callback

        # 初始化扫描状态
        self.scanning = False

        # 初始化MessageDialog和权限检查器
        self.message_dialog = MessageDialog(root)
        self.permission_checker = PermissionChecker()

        # 创建变量
        self.env_var = tk.StringVar(value="本机")
        self.wsl_var = tk.StringVar()
        self.docker_var = tk.StringVar()
        self.host_var = tk.StringVar(value="127.0.0.1")
        self.port_range_var = tk.StringVar(value="1-1000")
        self.thread_count_var = tk.StringVar(value="100")

        self._setup_style()
        self._create_widgets()
        self._setup_layout()
        self._bind_events()

        # 初始化环境选择
        self._on_env_change()

    def _setup_style(self):
        """设置UI样式"""
        self.style = ttk.Style()
        if platform.system() == "Windows":
            self.style.theme_use("vista")
        elif platform.system() == "Darwin":
            self.style.theme_use("aqua")
        else:
            self.style.theme_use("clam")

    def _create_widgets(self):
        """创建UI组件"""
        # 主框架
        self.main_frame = ttk.Frame(self.root, padding="10")

        # 环境选择
        self.env_frame = ttk.LabelFrame(self.main_frame, text="扫描环境", padding="5")
        self.env_var = tk.StringVar(value="host")

        self.host_radio = ttk.Radiobutton(
            self.env_frame, text="本机", variable=self.env_var, value="host"
        )
        self.wsl_radio = ttk.Radiobutton(
            self.env_frame, text="WSL", variable=self.env_var, value="wsl"
        )
        self.docker_radio = ttk.Radiobutton(
            self.env_frame, text="Docker", variable=self.env_var, value="docker"
        )

        # WSL发行版选择
        self.wsl_frame = ttk.Frame(self.env_frame)
        ttk.Label(self.wsl_frame, text="发行版:").pack(side=tk.LEFT)
        self.wsl_var = tk.StringVar()
        self.wsl_combo = ttk.Combobox(
            self.wsl_frame, textvariable=self.wsl_var, state="readonly", width=15
        )
        self.wsl_combo.pack(side=tk.LEFT, padx=5)

        # Docker容器选择
        self.docker_frame = ttk.Frame(self.env_frame)
        ttk.Label(self.docker_frame, text="容器:").pack(side=tk.LEFT)
        self.docker_var = tk.StringVar()
        self.docker_combo = ttk.Combobox(
            self.docker_frame, textvariable=self.docker_var, state="readonly", width=15
        )
        self.docker_combo.pack(side=tk.LEFT, padx=5)

        # 扫描参数
        self.param_frame = ttk.LabelFrame(self.main_frame, text="扫描参数", padding="5")

        # 目标主机
        self.host_frame = ttk.Frame(self.param_frame)
        ttk.Label(self.host_frame, text="目标主机:").pack(side=tk.LEFT)
        self.host_var = tk.StringVar(value="localhost")
        self.host_entry = ttk.Entry(
            self.host_frame, textvariable=self.host_var, width=20
        )
        self.host_entry.pack(side=tk.LEFT, padx=5)

        # 端口范围
        self.port_frame = ttk.Frame(self.param_frame)
        ttk.Label(self.port_frame, text="端口范围:").pack(side=tk.LEFT)
        self.start_port_var = tk.StringVar(value="1")
        self.start_port_entry = ttk.Entry(
            self.port_frame, textvariable=self.start_port_var, width=8
        )
        self.start_port_entry.pack(side=tk.LEFT, padx=2)

        ttk.Label(self.port_frame, text="-").pack(side=tk.LEFT)

        self.end_port_var = tk.StringVar(value="1000")
        self.end_port_entry = ttk.Entry(
            self.port_frame, textvariable=self.end_port_var, width=8
        )
        self.end_port_entry.pack(side=tk.LEFT, padx=2)

        # 线程数
        self.thread_frame = ttk.Frame(self.param_frame)
        ttk.Label(self.thread_frame, text="线程数:").pack(side=tk.LEFT)
        self.thread_var = tk.StringVar(value="100")
        self.thread_entry = ttk.Entry(
            self.thread_frame, textvariable=self.thread_var, width=8
        )
        self.thread_entry.pack(side=tk.LEFT, padx=5)

        # 控制按钮
        self.button_frame = ttk.Frame(self.main_frame)

        self.scan_button = ttk.Button(
            self.button_frame, text="开始扫描", command=self._on_scan_click
        )

        self.cancel_button = ttk.Button(
            self.button_frame,
            text="取消扫描",
            command=self._on_cancel_click,
            state="disabled",
        )

        self.clear_button = ttk.Button(
            self.button_frame, text="清除结果", command=self._clear_results
        )

        self.export_button = ttk.Button(
            self.button_frame, text="导出结果", command=self._export_results
        )

        self.permission_button = ttk.Button(
            self.button_frame, text="权限检查", command=self._check_permissions
        )

        # 进度区域
        self.progress_frame = ttk.Frame(self.main_frame)

        self.progress = ttk.Progressbar(self.progress_frame, mode="determinate")
        self.progress_label = ttk.Label(self.progress_frame, text="")

        # 状态栏
        self.status_var = tk.StringVar(value="就绪")
        self.status_bar = ttk.Label(
            self.main_frame, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W
        )
        
        # 用户角色显示标签
        self.user_role_var = tk.StringVar()
        self.user_role_label = ttk.Label(
            self.main_frame, textvariable=self.user_role_var, relief=tk.SUNKEN, anchor=tk.E
        )
        self._update_user_role()

        # 结果区域
        self.result_frame = ttk.LabelFrame(
            self.main_frame, text="扫描结果", padding="5"
        )

        # 创建树状视图
        columns = ("port", "status", "service", "process")
        self.tree = ttk.Treeview(self.result_frame, columns=columns, show="headings")

        # 定义列
        self.tree.column("port", width=80, anchor=tk.CENTER)
        self.tree.column("status", width=80, anchor=tk.CENTER)
        self.tree.column("service", width=150, anchor=tk.CENTER)
        self.tree.column("process", width=250, anchor=tk.CENTER)

        # 定义列标题
        self.tree.heading("port", text="端口号")
        self.tree.heading("status", text="状态")
        self.tree.heading("service", text="服务")
        self.tree.heading("process", text="进程信息")

        # 滚动条
        self.tree_scrollbar = ttk.Scrollbar(
            self.result_frame, orient=tk.VERTICAL, command=self.tree.yview
        )
        self.tree.configure(yscrollcommand=self.tree_scrollbar.set)

    def _setup_layout(self):
        """设置布局"""
        self.main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))

        # 环境选择布局
        self.env_frame.grid(row=0, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5)
        self.host_radio.grid(row=0, column=0, sticky=tk.W, padx=5)
        self.wsl_radio.grid(row=0, column=1, sticky=tk.W, padx=5)
        self.docker_radio.grid(row=0, column=2, sticky=tk.W, padx=5)
        self.wsl_frame.grid(row=1, column=0, columnspan=3, sticky=tk.W, pady=2)
        self.docker_frame.grid(row=2, column=0, columnspan=3, sticky=tk.W, pady=2)

        # 参数布局
        self.param_frame.grid(
            row=1, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5
        )
        self.host_frame.grid(row=0, column=0, sticky=tk.W, pady=2)
        self.port_frame.grid(row=1, column=0, sticky=tk.W, pady=2)
        self.thread_frame.grid(row=2, column=0, sticky=tk.W, pady=2)

        # 按钮布局
        self.button_frame.grid(
            row=2, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5
        )
        self.scan_button.pack(side=tk.LEFT, padx=5)
        self.cancel_button.pack(side=tk.LEFT, padx=5)
        self.clear_button.pack(side=tk.LEFT, padx=5)
        self.export_button.pack(side=tk.LEFT, padx=5)
        self.permission_button.pack(side=tk.LEFT, padx=5)

        # 进度布局
        self.progress_frame.grid(
            row=3, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5
        )
        self.progress.grid(row=0, column=0, sticky=(tk.W, tk.E), pady=2)
        self.progress_label.grid(row=1, column=0, sticky=tk.W, pady=2)

        # 状态栏布局
        self.status_bar.grid(row=5, column=0, sticky=(tk.W, tk.E), pady=5)
        
        # 用户角色标签布局
        self.user_role_label.grid(row=5, column=1, sticky=(tk.W, tk.E), pady=5, padx=(5, 0))

        # 结果区域布局
        self.result_frame.grid(
            row=4, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5
        )
        self.tree.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        self.tree_scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))

        # 配置权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        self.main_frame.columnconfigure(1, weight=1)
        self.main_frame.rowconfigure(4, weight=1)
        self.result_frame.columnconfigure(0, weight=1)
        self.result_frame.rowconfigure(0, weight=1)
        self.progress_frame.columnconfigure(0, weight=1)

    def _bind_events(self):
        """绑定事件"""
        self.env_var.trace("w", self._on_env_change)
        self._on_env_change()  # 初始化显示状态
        self._refresh_wsl_distros()
        self._refresh_docker_containers()

    def _on_env_change(self, *args):
        """环境选择变化事件"""
        env = self.env_var.get()

        if env == "wsl":
            self.wsl_frame.grid()
            self.docker_frame.grid_remove()
        elif env == "docker":
            self.wsl_frame.grid_remove()
            self.docker_frame.grid()
        else:
            self.wsl_frame.grid_remove()
            self.docker_frame.grid_remove()

    def _refresh_wsl_distros(self):
        """刷新WSL发行版列表"""
        try:
            result = subprocess.run(
                "wsl -l -q",
                shell=True,
                capture_output=True,
                text=True,
                encoding="utf-16le",
                errors="ignore",
            )

            if result.returncode == 0:
                distros = [
                    line.strip()
                    for line in result.stdout.strip().split("\n")
                    if line.strip()
                ]
                self.wsl_combo["values"] = distros
                if distros:
                    self.wsl_combo.set(distros[0])
        except Exception:
            pass

    def _refresh_docker_containers(self):
        """刷新Docker容器列表"""
        try:
            result = subprocess.run(
                "docker ps --format {{.Names}}",
                shell=True,
                capture_output=True,
                text=True,
            )

            if result.returncode == 0:
                containers = [
                    line.strip()
                    for line in result.stdout.strip().split("\n")
                    if line.strip()
                ]
                self.docker_combo["values"] = containers
                if containers:
                    self.docker_combo.set(containers[0])
        except Exception:
            pass

    def _on_scan_click(self):
        """扫描按钮点击事件"""
        if self.scan_callback:
            self.scan_callback()

    def _on_cancel_click(self):
        """取消按钮点击事件"""
        if self.cancel_callback:
            self.cancel_callback()

    def _clear_results(self):
        """清除结果"""
        for item in self.tree.get_children():
            self.tree.delete(item)

    def _export_results(self):
        """导出结果"""
        try:
            from tkinter import filedialog
            import csv

            if not self.tree.get_children():
                self.show_message("警告", "没有可导出的结果")
                return

            filename = filedialog.asksaveasfilename(
                defaultextension=".csv",
                filetypes=[("CSV files", "*.csv"), ("All files", "*.*")],
            )

            if filename:
                with open(filename, "w", newline="", encoding="utf-8") as csvfile:
                    writer = csv.writer(csvfile)
                    writer.writerow(["端口号", "状态", "服务", "进程信息"])

                    for item in self.tree.get_children():
                        values = self.tree.item(item)["values"]
                        writer.writerow(values)

                self.show_message("成功", f"结果已导出到: {filename}", "success")

        except Exception as e:
                error_msg = str(e)
                self.show_message("错误", f"导出失败: {error_msg}", "error")
            

    def get_scan_params(self) -> dict:
        """获取扫描参数"""
        return {
            "env": self.env_var.get(),
            "host": self.host_var.get(),
            "start_port": int(self.start_port_var.get()),
            "end_port": int(self.end_port_var.get()),
            "max_threads": int(self.thread_var.get()),
            "wsl_distro": self.wsl_var.get(),
            "docker_container": self.docker_var.get(),
        }

    def set_scanning_state(self, scanning: bool):
        """设置扫描状态"""
        self.scanning = scanning
        self.scan_button.config(state="disabled" if scanning else "normal")
        self.cancel_button.config(state="normal" if scanning else "disabled")

    def update_progress(self, completed: int, total: int, current_port: int):
        """更新进度"""
        self.progress.config(maximum=total, value=completed)
        self.progress_label.config(
            text=f"已扫描: {completed}/{total} - 当前端口: {current_port}"
        )

    def set_status(self, status: str):
        """设置状态"""
        self.status_var.set(status)

    def add_result(self, port: int, status: str, service: str, process: str):
        """添加扫描结果"""
        self.tree.insert("", "end", values=(port, status, service, process))

    # 删除 show_message 方法中的重复实现，直接使用 MessageDialog
    def show_message(self, title: str, message: str, msg_type: str = "info", width: int = 400, height: int = 200):
        """显示消息对话框"""
        self.message_dialog.show(title, message, msg_type, width, height)
    
    # 删除 _darken_color 方法，使用 MessageDialog 中的实现
    def _darken_color(self, color: str, factor: float = 0.8) -> str:
        """将颜色变暗"""
        if color.startswith("#"):
            color = color[1:]

        try:
            r = int(color[0:2], 16)
            g = int(color[2:4], 16)
            b = int(color[4:6], 16)

            r = int(r * factor)
            g = int(g * factor)
            b = int(b * factor)

            return f"#{r:02x}{g:02x}{b:02x}"
        except:
            return color

    def _check_permissions(self):
        """检查权限按钮点击事件"""
        try:
            # 获取当前选择的环境
            current_env = self.env_var.get()
            env_map = {"host": "host", "wsl": "wsl", "docker": "docker"}
            scan_env = env_map.get(current_env, "host")

            # 执行权限检查
            summary = self.permission_checker.get_permission_summary(scan_env)

            # 显示检查结果
            self.show_message("权限检查结果", summary, "info", width=400, height=400)
        except Exception as e:
            self.show_message("错误", f"权限检查失败: {str(e)}", "error")
    
    def _update_user_role(self):
        """更新用户角色显示"""
        try:
            if self.permission_checker.is_admin:
                self.user_role_var.set("管理员")
            else:
                self.user_role_var.set("普通用户")
        except Exception:
            self.user_role_var.set("未知")
